library(beeswarm)
library(data.table)
library(dichromat)
library(dplyr)
library(factoextra)
library(fmsb)
library(ggplot2)
library(gridExtra)
library(qdap)
library(RANN)
library(RColorBrewer)
library(readtext)
library(rvest)
library(scales)
library(sentimentr)
library(stopwords)
library(stringr)
library(syuzhet)
library(tibble)
library(tidytext)
library(tidyverse)
library(tm)
library(topicmodels)
library(wesanderson)
library(wordcloud)
source("../lib/plot_stacked.R")
source("../lib/speech_funcs.R")
source("../lib/helper_funcs.R")
# df <- read.csv("../data/philosophy_data.csv")

# Read data using data.table to decrease runtime
df <- data.table::fread("../output/philosophy_data_table.csv")

df <- df %>%
  group_by(school) %>%
  mutate(mode_date = find_mode(original_publication_date)) %>%
  ungroup() %>%
  mutate(school = ifelse(school == "german_idealism", "German Idealism", str_to_title(school)),
         school_ordered = reorder(factor(school), mode_date, mean, order = TRUE))

palette <- get_palette(length(unique(df$school)))

Overview

par(mfrow = c(4, 4))
i <- 0
for(s in levels(df$school_ordered)) {
  docs <- Corpus(VectorSource(df[df$school == s, ]$sentence_str)) %>%
    tm_map(tolower) %>%
    tm_map(removePunctuation) %>%
    tm_map(removeNumbers) %>%
    tm_map(removeWords, stopwords("english")) %>%
    tm_map(stripWhitespace)
  
  tdm <- TermDocumentMatrix(docs)
  tdm_tidy <- tidy(tdm)
  tdm_overall <- summarise(group_by(tdm_tidy, term), sum(count))
  
  i <- i + 1
  plt_title <- s
  wordcloud(tdm_overall$term, tdm_overall$`sum(count)`,
            scale = c(5, 0.5),
            max.words = 200,
            min.freq = 1,
            random.order = FALSE,
            rot.per = 0.3,
            random.color = FALSE,
            colors = palette[i])
  mtext(plt_title, side = 3)
}

df %>%
  unnest_tokens(bigram, sentence_str, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>%
  filter(!word1 %in% stopwords::stopwords(source = "snowball")) %>%
  filter(!word2 %in% stopwords::stopwords(source = "snowball")) %>%
  filter(!is.na(word1)) %>%
  filter(!is.na(word2)) %>%
  unite(bigram, word1, word2, sep = " ") %>%
  group_by(school_ordered, bigram) %>%
  summarize(n_bigram = n()) %>%
  slice_max(n_bigram, n = 10) %>%
  mutate(bigram = reorder_within(bigram, n_bigram, school_ordered)) %>%
  ggplot(aes(x = bigram, y = n_bigram, fill = school_ordered)) +
  geom_bar(stat = "identity", show.legend = FALSE) +
  facet_wrap(~school_ordered, scales = "free") +
  coord_flip() +
  scale_x_reordered() +
  scale_fill_manual(values = get_palette(length(unique(df$school)))) +
  labs(title = "Top 10 Bigrams by School", x = element_blank(), y = "Count") +
  theme_classic()

Philosophy speech

df %>%
  ggplot(aes(x = sentence_length, fill = school_ordered)) +
  geom_histogram(binwidth = 2, size = 0.25, show.legend = FALSE) +
  xlim(0, 500) +
  facet_grid(rows = vars(school_ordered)) +
  scale_fill_manual(values = palette) +
  labs(title = "Sentence Length by School", x = "Word count", y = "Sentence count") +
  theme_classic()

trend_plt <- df %>%
  group_by(original_publication_date) %>%
  summarize(avg_sentence_length = round(mean(sentence_length), 0)) %>%
  ggplot(aes(x = original_publication_date, y = avg_sentence_length)) +
  geom_line(stat = "identity", show.legend = FALSE) +
  guides(x = guide_axis(angle = 45)) +
  scale_fill_manual(values = palette) +
  labs(title = "Average Sentence Length over Time", x = "Year", y = "Word count") +
  theme_classic()
bar_plt <- df %>%
  group_by(school_ordered) %>%
  summarize(avg_sentence_length = round(mean(sentence_length), 0)) %>%
  ggplot(aes(x = school_ordered, y = avg_sentence_length, fill = school_ordered)) +
  geom_bar(stat = "identity", show.legend = FALSE) +
  guides(x = guide_axis(angle = 45)) +
  scale_fill_manual(values = palette) +
  labs(title = "Average Sentence Length by School", x = "School", y = "Word count") +
  theme_classic()
grid.arrange(trend_plt, bar_plt, nrow = 1)

df_distinct_word <- df %>%
  unnest_tokens(word, sentence_str) %>%
  filter(!(word %in% stopwords::stopwords(source = "snowball")))
trend_plt <- df_distinct_word %>%
  group_by(original_publication_date) %>%
  summarize(ndistinct_word = length(unique(word))) %>%
  ggplot(aes(x = original_publication_date, y = ndistinct_word)) +
  geom_line(stat = "identity", show.legend = FALSE) +
  guides(x = guide_axis(angle = 45)) +
  scale_fill_manual(values = palette) +
  labs(title = "Number of Distinct Words over Time", x = "Year", y = "Word count") +
  theme_classic()
bar_plt <- df_distinct_word %>%
  group_by(school_ordered) %>%
  summarize(ndistinct_word = length(unique(word))) %>%
  ggplot(aes(x = school_ordered, y = ndistinct_word, fill = school_ordered)) +
  geom_bar(stat = "identity", show.legend = FALSE) +
  guides(x = guide_axis(angle = 45)) +
  scale_fill_manual(values = palette) +
  labs(title = "Number of Distinct Words by School", x = "School", y = "Word count") +
  theme_classic()
grid.arrange(trend_plt, bar_plt, nrow = 1)

Sentiment analysis

emotions <- data.table::fread("../output/emotions.csv")
df_emotions <- cbind(df, emotions)
par(mfrow = c(4, 4))
i <- 0
for(s in levels(df$school_ordered)) {
  emotions_by_school <- df_emotions %>%
    mutate(school = ifelse(school == "german_idealism", "German Idealism", str_to_title(school))) %>%
    filter(school == s) %>%
    dplyr::select(anger, anticipation, disgust, fear, joy, sadness, surprise, trust) %>%
    bind_rows(summarise_all(., ~if(is.numeric(.)) sum(.) else "Total")) %>%
    slice_tail(n = 1) %>%
    as.data.frame()
  emotions_by_school <- rbind(rep(max(emotions_by_school), 8), rep(min(emotions_by_school), 8), emotions_by_school)
  
  i <- i + 1
  plt_title <- s
  radarchart(emotions_by_school, title = plt_title,
           pcol = palette[i], pfcol = alpha(palette[i], 0.3), plwd = 2,
           cglcol = "grey", cglty = 1, axislabcol = "grey", caxislabels = seq(0,20,5))
}

LS0tCnRpdGxlOiAiUHJvamVjdCAxOiBIaXN0b3J5IG9mIFBoaWxvc29waHkiCmF1dGhvcjogIktpZXUtR2lhbmcgTmd1eWVuIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShiZWVzd2FybSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGRpY2hyb21hdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGZtc2IpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkocWRhcCkKbGlicmFyeShSQU5OKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShyZWFkdGV4dCkKbGlicmFyeShydmVzdCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoc2VudGltZW50cikKbGlicmFyeShzdG9wd29yZHMpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShzeXV6aGV0KQpsaWJyYXJ5KHRleHRyZXVzZSkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHRvcGljbW9kZWxzKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpsaWJyYXJ5KHdvcmRjbG91ZCkKCnNvdXJjZSgiLi4vbGliL3Bsb3Rfc3RhY2tlZC5SIikKc291cmNlKCIuLi9saWIvc3BlZWNoX2Z1bmNzLlIiKQpzb3VyY2UoIi4uL2xpYi9oZWxwZXJfZnVuY3MuUiIpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgZGYgPC0gcmVhZC5jc3YoIi4uL2RhdGEvcGhpbG9zb3BoeV9kYXRhLmNzdiIpCgojIFJlYWQgZGF0YSB1c2luZyBkYXRhLnRhYmxlIHRvIGRlY3JlYXNlIHJ1bnRpbWUKZGYgPC0gZGF0YS50YWJsZTo6ZnJlYWQoIi4uL291dHB1dC9waGlsb3NvcGh5X2RhdGFfdGFibGUuY3N2IikKCmRmIDwtIGRmICU+JQogIGdyb3VwX2J5KHNjaG9vbCkgJT4lCiAgbXV0YXRlKG1vZGVfZGF0ZSA9IGZpbmRfbW9kZShvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShzY2hvb2wgPSBpZmVsc2Uoc2Nob29sID09ICJnZXJtYW5faWRlYWxpc20iLCAiR2VybWFuIElkZWFsaXNtIiwgc3RyX3RvX3RpdGxlKHNjaG9vbCkpLAogICAgICAgICBzY2hvb2xfb3JkZXJlZCA9IHJlb3JkZXIoZmFjdG9yKHNjaG9vbCksIG1vZGVfZGF0ZSwgbWVhbiwgb3JkZXIgPSBUUlVFKSkKCnBhbGV0dGUgPC0gZ2V0X3BhbGV0dGUobGVuZ3RoKHVuaXF1ZShkZiRzY2hvb2wpKSkKYGBgCgojIE92ZXJ2aWV3CgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93ID0gYyg0LCA0KSkKCmkgPC0gMApmb3IocyBpbiBsZXZlbHMoZGYkc2Nob29sX29yZGVyZWQpKSB7CiAgZG9jcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGRmW2RmJHNjaG9vbCA9PSBzLCBdJHNlbnRlbmNlX3N0cikpICU+JQogICAgdG1fbWFwKHRvbG93ZXIpICU+JQogICAgdG1fbWFwKHJlbW92ZVB1bmN0dWF0aW9uKSAlPiUKICAgIHRtX21hcChyZW1vdmVOdW1iZXJzKSAlPiUKICAgIHRtX21hcChyZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpICU+JQogICAgdG1fbWFwKHN0cmlwV2hpdGVzcGFjZSkKICAKICB0ZG0gPC0gVGVybURvY3VtZW50TWF0cml4KGRvY3MpCiAgdGRtX3RpZHkgPC0gdGlkeSh0ZG0pCiAgdGRtX292ZXJhbGwgPC0gc3VtbWFyaXNlKGdyb3VwX2J5KHRkbV90aWR5LCB0ZXJtKSwgc3VtKGNvdW50KSkKICAKICBpIDwtIGkgKyAxCiAgcGx0X3RpdGxlIDwtIHMKICB3b3JkY2xvdWQodGRtX292ZXJhbGwkdGVybSwgdGRtX292ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgICBzY2FsZSA9IGMoNSwgMC41KSwKICAgICAgICAgICAgbWF4LndvcmRzID0gMjAwLAogICAgICAgICAgICBtaW4uZnJlcSA9IDEsCiAgICAgICAgICAgIHJhbmRvbS5vcmRlciA9IEZBTFNFLAogICAgICAgICAgICByb3QucGVyID0gMC4zLAogICAgICAgICAgICByYW5kb20uY29sb3IgPSBGQUxTRSwKICAgICAgICAgICAgY29sb3JzID0gcGFsZXR0ZVtpXSkKICBtdGV4dChwbHRfdGl0bGUsIHNpZGUgPSAzKQp9CmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CmRmICU+JQogIHVubmVzdF90b2tlbnMoYmlncmFtLCBzZW50ZW5jZV9zdHIsIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHN0b3B3b3Jkczo6c3RvcHdvcmRzKHNvdXJjZSA9ICJzbm93YmFsbCIpKSAlPiUKICBmaWx0ZXIoIXdvcmQyICVpbiUgc3RvcHdvcmRzOjpzdG9wd29yZHMoc291cmNlID0gInNub3diYWxsIikpICU+JQogIGZpbHRlcighaXMubmEod29yZDEpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHdvcmQyKSkgJT4lCiAgdW5pdGUoYmlncmFtLCB3b3JkMSwgd29yZDIsIHNlcCA9ICIgIikgJT4lCiAgZ3JvdXBfYnkoc2Nob29sX29yZGVyZWQsIGJpZ3JhbSkgJT4lCiAgc3VtbWFyaXplKG5fYmlncmFtID0gbigpKSAlPiUKICBzbGljZV9tYXgobl9iaWdyYW0sIG4gPSAxMCkgJT4lCiAgbXV0YXRlKGJpZ3JhbSA9IHJlb3JkZXJfd2l0aGluKGJpZ3JhbSwgbl9iaWdyYW0sIHNjaG9vbF9vcmRlcmVkKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYmlncmFtLCB5ID0gbl9iaWdyYW0sIGZpbGwgPSBzY2hvb2xfb3JkZXJlZCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofnNjaG9vbF9vcmRlcmVkLCBzY2FsZXMgPSAiZnJlZSIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfcmVvcmRlcmVkKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdldF9wYWxldHRlKGxlbmd0aCh1bmlxdWUoZGYkc2Nob29sKSkpKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgQmlncmFtcyBieSBTY2hvb2wiLCB4ID0gZWxlbWVudF9ibGFuaygpLCB5ID0gIkNvdW50IikgKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCiMgUGhpbG9zb3BoeSBzcGVlY2gKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpkZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZW50ZW5jZV9sZW5ndGgsIGZpbGwgPSBzY2hvb2xfb3JkZXJlZCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDIsIHNpemUgPSAwLjI1LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgeGxpbSgwLCA1MDApICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHNjaG9vbF9vcmRlcmVkKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gIlNlbnRlbmNlIExlbmd0aCBieSBTY2hvb2wiLCB4ID0gIldvcmQgY291bnQiLCB5ID0gIlNlbnRlbmNlIGNvdW50IikgKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD0zfQp0cmVuZF9wbHQgPC0gZGYgJT4lCiAgZ3JvdXBfYnkob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkgJT4lCiAgc3VtbWFyaXplKGF2Z19zZW50ZW5jZV9sZW5ndGggPSByb3VuZChtZWFuKHNlbnRlbmNlX2xlbmd0aCksIDApKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlLCB5ID0gYXZnX3NlbnRlbmNlX2xlbmd0aCkpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBndWlkZXMoeCA9IGd1aWRlX2F4aXMoYW5nbGUgPSA0NSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIFNlbnRlbmNlIExlbmd0aCBvdmVyIFRpbWUiLCB4ID0gIlllYXIiLCB5ID0gIldvcmQgY291bnQiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpiYXJfcGx0IDwtIGRmICU+JQogIGdyb3VwX2J5KHNjaG9vbF9vcmRlcmVkKSAlPiUKICBzdW1tYXJpemUoYXZnX3NlbnRlbmNlX2xlbmd0aCA9IHJvdW5kKG1lYW4oc2VudGVuY2VfbGVuZ3RoKSwgMCkpICU+JQogIGdncGxvdChhZXMoeCA9IHNjaG9vbF9vcmRlcmVkLCB5ID0gYXZnX3NlbnRlbmNlX2xlbmd0aCwgZmlsbCA9IHNjaG9vbF9vcmRlcmVkKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ3VpZGVzKHggPSBndWlkZV9heGlzKGFuZ2xlID0gNDUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBTZW50ZW5jZSBMZW5ndGggYnkgU2Nob29sIiwgeCA9ICJTY2hvb2wiLCB5ID0gIldvcmQgY291bnQiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpncmlkLmFycmFuZ2UodHJlbmRfcGx0LCBiYXJfcGx0LCBucm93ID0gMSkKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9M30KZGZfZGlzdGluY3Rfd29yZCA8LSBkZiAlPiUKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHNlbnRlbmNlX3N0cikgJT4lCiAgZmlsdGVyKCEod29yZCAlaW4lIHN0b3B3b3Jkczo6c3RvcHdvcmRzKHNvdXJjZSA9ICJzbm93YmFsbCIpKSkKCnRyZW5kX3BsdCA8LSBkZl9kaXN0aW5jdF93b3JkICU+JQogIGdyb3VwX2J5KG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUpICU+JQogIHN1bW1hcml6ZShuZGlzdGluY3Rfd29yZCA9IGxlbmd0aCh1bmlxdWUod29yZCkpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlLCB5ID0gbmRpc3RpbmN0X3dvcmQpKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ3VpZGVzKHggPSBndWlkZV9heGlzKGFuZ2xlID0gNDUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIERpc3RpbmN0IFdvcmRzIG92ZXIgVGltZSIsIHggPSAiWWVhciIsIHkgPSAiV29yZCBjb3VudCIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmJhcl9wbHQgPC0gZGZfZGlzdGluY3Rfd29yZCAlPiUKICBncm91cF9ieShzY2hvb2xfb3JkZXJlZCkgJT4lCiAgc3VtbWFyaXplKG5kaXN0aW5jdF93b3JkID0gbGVuZ3RoKHVuaXF1ZSh3b3JkKSkpICU+JQogIGdncGxvdChhZXMoeCA9IHNjaG9vbF9vcmRlcmVkLCB5ID0gbmRpc3RpbmN0X3dvcmQsIGZpbGwgPSBzY2hvb2xfb3JkZXJlZCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGd1aWRlcyh4ID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDQ1KSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBEaXN0aW5jdCBXb3JkcyBieSBTY2hvb2wiLCB4ID0gIlNjaG9vbCIsIHkgPSAiV29yZCBjb3VudCIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmdyaWQuYXJyYW5nZSh0cmVuZF9wbHQsIGJhcl9wbHQsIG5yb3cgPSAxKQpgYGAKCiMgU2VudGltZW50IGFuYWx5c2lzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZW1vdGlvbnMgPC0gZGF0YS50YWJsZTo6ZnJlYWQoIi4uL291dHB1dC9lbW90aW9ucy5jc3YiKQpkZl9lbW90aW9ucyA8LSBjYmluZChkZiwgZW1vdGlvbnMpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdyA9IGMoNCwgNCkpCgppIDwtIDAKZm9yKHMgaW4gbGV2ZWxzKGRmJHNjaG9vbF9vcmRlcmVkKSkgewogIGVtb3Rpb25zX2J5X3NjaG9vbCA8LSBkZl9lbW90aW9ucyAlPiUKICAgIG11dGF0ZShzY2hvb2wgPSBpZmVsc2Uoc2Nob29sID09ICJnZXJtYW5faWRlYWxpc20iLCAiR2VybWFuIElkZWFsaXNtIiwgc3RyX3RvX3RpdGxlKHNjaG9vbCkpKSAlPiUKICAgIGZpbHRlcihzY2hvb2wgPT0gcykgJT4lCiAgICBkcGx5cjo6c2VsZWN0KGFuZ2VyLCBhbnRpY2lwYXRpb24sIGRpc2d1c3QsIGZlYXIsIGpveSwgc2FkbmVzcywgc3VycHJpc2UsIHRydXN0KSAlPiUKICAgIGJpbmRfcm93cyhzdW1tYXJpc2VfYWxsKC4sIH5pZihpcy5udW1lcmljKC4pKSBzdW0oLikgZWxzZSAiVG90YWwiKSkgJT4lCiAgICBzbGljZV90YWlsKG4gPSAxKSAlPiUKICAgIGFzLmRhdGEuZnJhbWUoKQoKICBlbW90aW9uc19ieV9zY2hvb2wgPC0gcmJpbmQocmVwKG1heChlbW90aW9uc19ieV9zY2hvb2wpLCA4KSwgcmVwKG1pbihlbW90aW9uc19ieV9zY2hvb2wpLCA4KSwgZW1vdGlvbnNfYnlfc2Nob29sKQogIAogIGkgPC0gaSArIDEKICBwbHRfdGl0bGUgPC0gcwogIHJhZGFyY2hhcnQoZW1vdGlvbnNfYnlfc2Nob29sLCB0aXRsZSA9IHBsdF90aXRsZSwKICAgICAgICAgICBwY29sID0gcGFsZXR0ZVtpXSwgcGZjb2wgPSBhbHBoYShwYWxldHRlW2ldLCAwLjMpLCBwbHdkID0gMiwKICAgICAgICAgICBjZ2xjb2wgPSAiZ3JleSIsIGNnbHR5ID0gMSwgYXhpc2xhYmNvbCA9ICJncmV5IiwgY2F4aXNsYWJlbHMgPSBzZXEoMCwyMCw1KSkKfQpgYGAK